/*
 ### jQuery XML to JSON Plugin v1.1 - 2008-07-01 ###
 * http://www.fyneworks.com/ - diego@fyneworks.com
 * Dual licensed under the MIT and GPL licenses:
 *   http://www.opensource.org/licenses/mit-license.php
 *   http://www.gnu.org/licenses/gpl.html
 ###
 Website: http://www.fyneworks.com/jquery/xml-to-json/
*//*
 # INSPIRED BY: http://www.terracoder.com/
           AND: http://www.thomasfrank.se/xml_to_json.html
											AND: http://www.kawa.net/works/js/xml/objtree-e.html
*//*
 This simple script converts XML (document of code) into a JSON object. It is the combination of 2
 'xml to json' great parsers (see below) which allows for both 'simple' and 'extended' parsing modes.
*/
// Avoid collisions
function formToXml(frmid) {
    var a = formToJsonObject(document.getElementById(frmid))
    var util = new JsonToXml(false);
    var result = util.toXml(a).replace(/\\\"/g, '"');
    return result;
}
(function(win, $){

    var doc = win.document,
        nav = win.navigator,
        bro = {};

    //IE特有的条件编译，勿当做注释删除
    if(/*@cc_on 1 || @*/ 0){
        bro.msie = doc.documentMode || (doc.compatMode == "CSS1Compat" ? "XMLHttpRequest" in win ? 7 : 6 : 5)
        nav.language = nav.userLanguage;
    } else if ( win.opera ) {
        //Opera

        bro.opera = opera.version()
        nav.language = nav.language.replace(/-\w+$/, function(str ) {
            return str.toUpperCase();
        });

    } else if ( win.netscape && nav.product == "Gecko" ) {
        //Firefox

        try {
            bro.gecko = /\brv:\s?([\w.]+)\b/.exec(nav.userAgent)[1];
        } catch (ex) {
            bro.gecko = true;
        }

    } else {
        //WebKit

        //navigator.appVersion中取版本号
        function getver(name) {
            var sName = name.toLowerCase();
            try {
                bro[sName] = new RegExp(name + "\\/([\\w.]+)\\b").exec(nav.appVersion)[1];
            } catch (ex) {
                bro[sName] = true;
            }
        }

        //判定为webkit
        getver("WebKit");

        if(win.chrome){
            //判定为Chrome
            getver("Chrome");
        } else if(/^apple\s+/i.test(nav.vendor)) {
            //判定为Safari
            getver("Safari");
        }

    }

    $.browser = bro;

})(this, jQuery);

;if(window.jQuery) (function($){
 
 // Add function to jQuery namespace
 $.extend({
  
  // converts xml documents and xml text to json object
  xml2json: function(xml, extended) {
   if(!xml) return {}; // quick fail
   
   //### PARSER LIBRARY
   // Core function
   function parseXML(node, simple){
    if(!node) return null;
    var txt = '', obj = null, att = null;
    var nt = node.nodeType, nn = jsVar(node.localName || node.nodeName);
    var nv = node.text || node.nodeValue || '';
    /*DBG*/ //if(window.console) console.log(['x2j',nn,nt,nv.length+' bytes']);
    if(node.childNodes){
     if(node.childNodes.length>0){
      /*DBG*/ //if(window.console) console.log(['x2j',nn,'CHILDREN',node.childNodes]);
      $.each(node.childNodes, function(n,cn){
       var cnt = cn.nodeType, cnn = jsVar(cn.localName || cn.nodeName);
       var cnv = cn.text || cn.nodeValue || '';
       /*DBG*/ //if(window.console) console.log(['x2j',nn,'node>a',cnn,cnt,cnv]);
       if(cnt == 8){
        /*DBG*/ //if(window.console) console.log(['x2j',nn,'node>b',cnn,'COMMENT (ignore)']);
        return; // ignore comment node
       }
       else if(cnt == 3 || cnt == 4 || !cnn){
        // ignore white-space in between tags
        if(cnv.match(/^\s+$/)){
         /*DBG*/ //if(window.console) console.log(['x2j',nn,'node>c',cnn,'WHITE-SPACE (ignore)']);
         return;
        };
        /*DBG*/ //if(window.console) console.log(['x2j',nn,'node>d',cnn,'TEXT']);
        txt += cnv.replace(/^\s+/,'').replace(/\s+$/,'');
								// make sure we ditch trailing spaces from markup
       }
       else{
        /*DBG*/ //if(window.console) console.log(['x2j',nn,'node>e',cnn,'OBJECT']);
        obj = obj || {};
        if(obj[cnn]){
         /*DBG*/ //if(window.console) console.log(['x2j',nn,'node>f',cnn,'ARRAY']);
         
									// http://forum.jquery.com/topic/jquery-jquery-xml2json-problems-when-siblings-of-the-same-tagname-only-have-a-textnode-as-a-child
									if(!obj[cnn].length) obj[cnn] = myArr(obj[cnn]);
									obj[cnn] = myArr(obj[cnn]);
         
									obj[cnn][ obj[cnn].length ] = parseXML(cn, true/* simple */);
         obj[cnn].length = obj[cnn].length;
        }
        else{
         /*DBG*/ //if(window.console) console.log(['x2j',nn,'node>g',cnn,'dig deeper...']);
         obj[cnn] = parseXML(cn);
        };
       };
      });
     };//node.childNodes.length>0
    };//node.childNodes
    if(node.attributes){
     if(node.attributes.length>0){
      /*DBG*/ //if(window.console) console.log(['x2j',nn,'ATTRIBUTES',node.attributes])
      att = {}; obj = obj || {};
      $.each(node.attributes, function(a,at){
       var atn = jsVar(at.name), atv = at.value;
       att[atn] = atv;
       if(obj[atn]){
        /*DBG*/ //if(window.console) console.log(['x2j',nn,'attr>',atn,'ARRAY']);
        
								// http://forum.jquery.com/topic/jquery-jquery-xml2json-problems-when-siblings-of-the-same-tagname-only-have-a-textnode-as-a-child
								//if(!obj[atn].length) obj[atn] = myArr(obj[atn]);//[ obj[ atn ] ];
        obj[cnn] = myArr(obj[cnn]);
								
								obj[atn][ obj[atn].length ] = atv;
        obj[atn].length = obj[atn].length;
       }
       else{
        /*DBG*/ //if(window.console) console.log(['x2j',nn,'attr>',atn,'TEXT']);
        obj[atn] = atv;
       };
      });
      //obj['attributes'] = att;
     };//node.attributes.length>0
    };//node.attributes
    if(obj){
     obj = $.extend( (txt!='' ? new String(txt) : {}),/* {text:txt},*/ obj || {}/*, att || {}*/);
     txt = (obj.text) ? (typeof(obj.text)=='object' ? obj.text : [obj.text || '']).concat([txt]) : txt;
     if(txt) obj.text = txt;
     txt = '';
    };
    var out = obj || txt;
    //console.log([extended, simple, out]);
    if(extended){
     if(txt) out = {};//new String(out);
     txt = out.text || txt || '';
     if(txt) out.text = txt;
     if(!simple) out = myArr(out);
    };
    return out;
   };// parseXML
   // Core Function End
   // Utility functions
   var jsVar = function(s){ return String(s || '').replace(/-/g,"_"); };
   
			// NEW isNum function: 01/09/2010
			// Thanks to Emile Grau, GigaTecnologies S.L., www.gigatransfer.com, www.mygigamail.com
			function isNum(s){
				// based on utility function isNum from xml2json plugin (http://www.fyneworks.com/ - diego@fyneworks.com)
				// few bugs corrected from original function :
				// - syntax error : regexp.test(string) instead of string.test(reg)
				// - regexp modified to accept  comma as decimal mark (latin syntax : 25,24 )
				// - regexp modified to reject if no number before decimal mark  : ".7" is not accepted
				// - string is "trimmed", allowing to accept space at the beginning and end of string
				var regexp=/^((-)?([0-9]+)(([\.\,]{0,1})([0-9]+))?$)/
				return (typeof s == "number") || regexp.test(String((s && typeof s == "string") ? jQuery.trim(s) : ''));
			};
			// OLD isNum function: (for reference only)
			//var isNum = function(s){ return (typeof s == "number") || String((s && typeof s == "string") ? s : '').test(/^((-)?([0-9]*)((\.{0,1})([0-9]+))?$)/); };
																
   var myArr = function(o){
    
				// http://forum.jquery.com/topic/jquery-jquery-xml2json-problems-when-siblings-of-the-same-tagname-only-have-a-textnode-as-a-child
				//if(!o.length) o = [ o ]; o.length=o.length;
    if(!$.isArray(o)) o = [ o ]; o.length=o.length;
				
				// here is where you can attach additional functionality, such as searching and sorting...
    return o;
   };
   // Utility functions End
   //### PARSER LIBRARY END
   
   // Convert plain text to xml
   if(typeof xml=='string') xml = $.text2xml(xml);
   
   // Quick fail if not xml (or if this is a node)
   if(!xml.nodeType) return;
   if(xml.nodeType == 3 || xml.nodeType == 4) return xml.nodeValue;
   
   // Find xml root node
   var root = (xml.nodeType == 9) ? xml.documentElement : xml;
   
   // Convert xml to json
   var out = parseXML(root, true /* simple */);
   
   // Clean-up memory
   xml = null; root = null;
   
   // Send output
   return out;
  },
  
  // Convert text to XML DOM
  text2xml: function(str) {
   // NOTE: I'd like to use jQuery for this, but jQuery makes all tags uppercase
   //return $(xml)[0];
   var out;
   try{
    var xml = ($.browser.msie)?new ActiveXObject("Microsoft.XMLDOM"):new DOMParser();
    xml.async = false;
   }catch(e){ throw new Error("XML Parser could not be instantiated") };
   try{
    if($.browser.msie) out = (xml.loadXML(str))?xml:false;
    else out = xml.parseFromString(str, "text/xml");
   }catch(e){ throw new Error("Error parsing XML string") };
   return out;
  }
		
 }); // extend $

})(jQuery);

/**
 * Change JSON object to XML string.
 * The JSON object value must be a string,an array or object.
 * If the value is an integer or a float value,you must add " or ' to the value.
 * @author bitjjj
 * @param isPretty If format xml
 * @param separator Set line separator
 * @example var util = new JsonToXml(true); var result = util.toXml(JSONObject);
 * @return
 */
function JsonToXml(isPretty,separator){
	this.result=[];
	this.isPretty = !!isPretty;
	this.separator = separator || "\r\n";
	
	//this.result.push("<?xml version=\"1.0\" encoding=\"utf-8\"?>");
	if(this.isPretty){
		//this.result.push(this.separator);
	}
}

JsonToXml.prototype.spacialChars=["&","<",">","\"","'"];
//JsonToXml.prototype.validChars=["&amp;","&lt;","&gt;","&quot;","&apos;"];
JsonToXml.prototype.validChars=["&","<",">","\"","'"];

JsonToXml.prototype.toString = function(){
	return this.result.join("");
};

JsonToXml.prototype.replaceSpecialChar = function(s){
  
    for(var i=0;i<this.spacialChars.length;i++){
        s=s.replace(new RegExp(this.spacialChars[i],"g"),this.validChars[i]);
    }
    return s;
};

JsonToXml.prototype.appendText = function(s){
    s = this.replaceSpecialChar(s);
    this.result.push(s);
};


JsonToXml.prototype.appendFlagBegin = function(s){

	this.result.push("<"+s+">");
};

JsonToXml.prototype.appendFlagEnd = function(s){
	this.result.push("</"+s+">");
	if(this.isPretty){
		//this.result.push(this.separator);
	}
};

JsonToXml.prototype.each = function(arr,cb){
	for(var i=0;i<arr.length;i++){
		cb(i,arr[i]);
	}
};

/**
 * format xml string to pretty string
 * @param xml string
 * @return pretty xml string
 * @reference http://stackoverflow.com/questions/376373/pretty-printing-xml-with-javascript
 */
JsonToXml.prototype.formatXml = function (xml) {     
	var formatted = [];     
	var reg = /(>)(<)(\/*)/g;     
	xml = xml.replace(reg, '$1'+this.separator+'$2$3');     
	var pad = 0,self = this;     
	this.each(xml.split(this.separator), function(index, node) {         
			var indent = 0;         
			if (node.match( /.+<\/\w[^>]*>$/ )) {             
				indent = 0;         
			} 
			else if (node.match( /^<\/\w/ )) {             
				if (pad != 0) {                 
					pad -= 1;             
				}         
			} 
			else if (node.match( /^<\w[^>]*[^\/]>.*$/ )) {             
				indent = 1;         
			} 
			else {             
				indent = 0;         
			}          
			var padding = '';         
			for (var i = 0; i < pad; i++) {             
				padding += '  ';         
			}          
			formatted.push(padding + node + self.separator);         
			pad += indent;     
	});    
	return formatted.join(""); 
}; 

JsonToXml.prototype.toXml = function(json){
	this._toXml(json);
	
	if(this.isPretty){
		return this.formatXml(this.toString());
	}
	return this.toString();
};

JsonToXml.prototype._toXml = function(json){
   
    for(var tag in json){	
    	//need to handle Array object specially
    	if(json[tag].constructor==Array){
    		for(var i=0;i<json[tag].length;i++){
    			this.appendFlagBegin(tag);
    			var item = json[tag][i];
    			if(item.constructor == Object){
    				this._toXml(item);
    			}
    			else if(item.constructor == Array){
    				var obj={};
    				obj[tag]=item;
    				this._toXml(obj);
    			}
    			else if(item.constructor == String){
    	            this.appendText('<![CDATA['+item+']]>');
    	        }
    			this.appendFlagEnd(tag);
    		}
    	}
    	else{
	        this.appendFlagBegin(tag);
	        if(json[tag].constructor==Object){
	            this._toXml(json[tag]);
	        }
	        else if(json[tag].constructor==String){
	            this.appendText('<![CDATA['+json[tag]+']]>');
	        }
	        this.appendFlagEnd(tag);
    	}
    }
};
(function($) {
    
    $.fn.xslt = function() {
        return this;
    }
    
    var str = /^\s*</;
    if (document.recalc) { // IE 5+
        $.fn.xslt = function(xml, xslt, callback) {//, callback
            var target = $(this);
            var xm = new ActiveXObject("Microsoft.XMLDOM");
            xm.async = false;
            xm.loadXML(xml);
            $.get(xslt, function(data) {
             target.html(xm.transformNode(data));             
             if(typeof(callback) === 'function' ) callback.apply(this); 
             });
            return this;
        };
    }
    else if ($.browser.msie && $.browser.version == "9.0") { //IE9

        $.fn.xslt = function(xml, xslt, callback) {  
            if (window.ActiveXObject) {  
                var target = $(this);  
                
                var xmlDoc = new ActiveXObject("Msxml2.DOMDocument.6.0"); 
	           //裝載數據
	            xmlDoc.async = false; 
	            xmlDoc.loadXML(xml);    
		       //裝載樣式
		        var xslDoc = new ActiveXObject("Msxml2.DOMDocument.6.0"); 
		        xslDoc.async = false; 
		        xslDoc.resolveExternals = false; 
		        xslDoc.load(xslt);  
				target.html(xmlDoc.transformNode(xslDoc));                       
                if(typeof(callback) === 'function' ) callback.apply(this); 
            }  
            return this;  
        };  
    } 
    else if (window.DOMParser != undefined && window.XMLHttpRequest != undefined && window.XSLTProcessor != undefined) { // Mozilla 0.9.4+, Opera 9+
        var processor = new XSLTProcessor();
        var support = false;
        if ($.isFunction(processor.transformDocument)) {
            support = window.XMLSerializer != undefined;
        }
        else {
            support = true;
        }
        if (support) {
            $.fn.xslt = function(xml, xslt, callback) {
                var target = $(this);
                var transformed = false;
                var xm = {
                    readyState: 4
                };
                var xs = {
                    readyState: 4
                };

                var change = function() {
                    if (xm.readyState == 4 && xs.readyState == 4 && !transformed) {

                        var processor = new XSLTProcessor();
                        if ($.isFunction(processor.transformDocument)) {
                            // obsolete Mozilla interface
                            resultDoc = document.implementation.createDocument("", "", null);
                            processor.transformDocument(xm.responseXML, xs.responseXML, resultDoc, null);
                            target.html(new XMLSerializer().serializeToString(resultDoc));                               
                        }
                        else {
                            processor.importStylesheet(xs.responseXML);
                            resultDoc = processor.transformToFragment(xm.responseXML, document);
                            target.empty().append(resultDoc);                                                
                        }
                        transformed = true;
                        if(typeof(callback) === 'function' ) callback.apply(this); 
                    }
                };
                
                
                if (str.test(xml)) {

                    xm.responseXML = new DOMParser().parseFromString(xml, "text/xml");
                }
                else {

                    xm = $.ajax({ dataType: "xml", url: xml });
                    xm.onreadystatechange = change;
                }

                if (str.test(xslt)) {

                    xs.responseXML = new DOMParser().parseFromString(xslt, "text/xml");
                    change();
                }
                else {

                    xs = $.ajax({ dataType: "xml", url: xslt });
                    xs.onreadystatechange = change;
                }
                return this;
            };

        }
    }
})(jQuery);


/** 
**json对象数据设置到表单域中 
*/
function jsonObjectToForm(form, jsonObject) {
  for (i = 0, max = form.elements.length; i < max; i++) {
    e = form.elements[i];
    eName = e.name;
    if (eName.indexOf('.') > 0) {
      dotIndex = eName.indexOf('.');
      parentName = eName.substring(0, dotIndex);
      childName = eName.substring(dotIndex + 1);
      //迭代判断eName，组装成json数据结构 
      eValue = iterValueFromJsonObject(jsonObject, parentName, childName);
    } else {
      eValue = jsonObject[eName];
    }
    if (eValue && eValue != "undefined" && eValue != "null") {
      switch (e.type) {
      case 'checkbox':
      case 'radio':
        if (e.value == eValue) {
          e.checked = true;
        }
        break;
      case 'hidden':
      case 'password':
      case 'textarea':
      case 'text':
        e.value = eValue;
        break;
      case 'select-one':
      case 'select-multiple':
        for (j = 0; j < e.options.length; j++) {
          op = e.options[j];
          //alert("eName : " + eName + "; op value : " + op.value + "; eValue : " + eValue); 
          if (op.value == eValue) {
            op.selected = true;
          }
        }
        break;
      case 'button':
      case 'file':
      case 'image':
      case 'reset':
      case 'submit':
      default:
      }
    }
  }
}

/** 
* json数组读写有两种方式 
* 1: a.bs[0].id 
* 2: a["bs"][0]["id"] 
* 把表单转换成json数据格式 
*/
function formToJsonObject(form) {
  var jsonObject = {};
  for (i = 0, max = form.elements.length; i < max; i++) {
    e = form.elements[i];
    em = new Array();
    if (e.type == 'select-multiple') {
      for (j = 0; j < e.options.length; j++) {
        op = e.options[j];
        if (op.selected) {
          em[em.length] = op.value;
        }
      }
    }
	if(!e.name) continue;
    switch (e.type) {
    case 'checkbox':
    case 'radio':
      if (!e.checked) {
        break;
      }
    case 'hidden':
    case 'password':
    case 'select-one':
    case 'select-multiple':
    case 'textarea':
    case 'text':
      eName = e.name;
      if (e.type == 'select-multiple') {
        eValue = em;
      } else {
        eValue = e.value.replace(new RegExp('(["\\\\])', 'g'), '\\$1').replace(new RegExp('\\r\\n', 'g'), '\n');
      }
      //判断是否是对象类型数据 
      if (eName.indexOf('.') > 0) {
        dotIndex = eName.indexOf('.');
        parentName = eName.substring(0, dotIndex);
        childName = eName.substring(dotIndex + 1);
        //迭代判断eName，组装成json数据结构 
        iterJsonObject(jsonObject, parentName, childName, eValue);
      } else {
        jsonObject[eName] = eValue;
      }
      break;
    case 'button':
    case 'file':
    case 'image':
    case 'reset':
    case 'submit':
    default:
    }
  }
  return jsonObject;
}

/** 
* 把表单元素迭代转换成json数据 
*/
function iterJsonObject(jsonObject, parentName, childName, eValue) {
  //pArrayIndex用于判断元素是否是数组标示 
  pArrayIndex = parentName.indexOf('[');
  //判断是否集合数据，不是则只是对象属性 
  if (pArrayIndex < 0) {
    var child = jsonObject[parentName];
    if (!child) {
      jsonObject[parentName] = {};
    }
    dotIndex = childName.indexOf('.');
    if (dotIndex > 0) {
      iterJsonObject(jsonObject[parentName], childName.substring(0, dotIndex), childName.substring(dotIndex + 1), eValue);
    } else {
      jsonObject[parentName][childName] = eValue;
    }
  } else {
    pArray = jsonObject[parentName.substring(0, pArrayIndex)];
    //若不存在js数组，则初始化一个数组类型 
    if (!pArray) {
      jsonObject[parentName.substring(0, pArrayIndex)] = new Array();
    }
    //取得集合下标，并判断对应下标是否存在js对象 
    arrayIndex = parentName.substring(pArrayIndex + 1, parentName.length - 1);
		//重置索引
		if(arrayIndex=='') arrayIndex = jsonObject[parentName.substring(0, pArrayIndex)].length;
    var c = jsonObject[parentName.substring(0, pArrayIndex)][arrayIndex];
    if (!c) {
      jsonObject[parentName.substring(0, pArrayIndex)][arrayIndex] = {};
    }
    dotIndex = childName.indexOf('.');
    if (dotIndex > 0) {
      iterJsonObject(jsonObject[parentName.substring(0, pArrayIndex)][arrayIndex], childName.substring(0, dotIndex), childName.substring(dotIndex + 1), eValue);
    } else {
      jsonObject[parentName.substring(0, pArrayIndex)][arrayIndex][childName] = eValue;
    }
  }
}

/** 
* 迭代json数据对象设置到表单域中 
*/
function iterValueFromJsonObject(jsonObject, parentName, childName) {
  //pArrayIndex用于判断元素是否是数组标示 
  pArrayIndex = parentName.indexOf('[');
  //判断是否集合数据，不是则只是对象属性 
  if (pArrayIndex < 0) {
    dotIndex = childName.indexOf('.');
    if (dotIndex > 0) {
      return iterValueFromJsonObject(jsonObject[parentName], childName.substring(0, dotIndex), childName.substring(dotIndex + 1));
    } else {
      return jsonObject[parentName][childName]
    }
  } else {
    pArray = jsonObject[parentName.substring(0, pArrayIndex)];
    //取得集合下标，并判断对应下标是否存在js对象 
    arrayIndex = parentName.substring(pArrayIndex + 1, parentName.length - 1);
    var c = jsonObject[parentName.substring(0, pArrayIndex)][arrayIndex];
    dotIndex = childName.indexOf('.');
    if (dotIndex > 0) {
      return iterValueFromJsonObject(jsonObject[parentName.substring(0, pArrayIndex)][arrayIndex], childName.substring(0, dotIndex), childName.substring(dotIndex + 1));
    } else {
      return jsonObject[parentName.substring(0, pArrayIndex)][arrayIndex][childName]
    }
  }
}